/* eslint-disable @typescript-eslint/no-explicit-any */
import { ValidationArguments, ValidationOptions, registerDecorator } from 'class-validator'
import { validateClass } from './custom_validate'
import { TypeUtils } from './type_utils'

interface ValidationOptionsEx extends ValidationOptions {
    validateNested?: boolean;
}

// eslint-disable-next-line @typescript-eslint/ban-types
export function ComplexType(originTypes?: (Function | undefined | null)[], validationOptions?: ValidationOptionsEx, eachTypes?: (Function | undefined | null)[]): Function {
    // 用于保存单个ComplexType each模式下List元素的校验结果
    const itemsValidatedErrMsgs: Array<string> = new Array<string>()

    return function (object: object, propertyName: string) {
        registerDecorator({
            name: 'complexType',
            target: object.constructor,
            propertyName: propertyName,
            options: validationOptions as any,
            validator: {
                validate(value: any, args: ValidationArguments) {
                    let types: any[] = []
                    // 哪怕是开启了each为true，如果字段本身就是null或undefined或string类型，则这里args.value和value都是null或undefined或string值
                    /* if (args.property == 'list') {
                        console.error(`FFFF:${validationOptions?.each} --- ${JSON.stringify(args?.value)} --- ${JSON.stringify(value)}`)
                    } */
                    // 即便开启了each，但是字段值的类型不是Array类型，那types也是用originTypes的
                    const eachFlag = validationOptions?.each === true && args.value instanceof Array
                    // 开启了each时，value是数组字段的单个元素，args.value才是整个字段的值
                    if (eachFlag) {
                        types = eachTypes as any
                    } else {
                        types = originTypes as any
                    }

                    let nestedErr = false
                    const result = types.some(type => {
                        // 如果type是Date类型，需要将值转换一下
                        if (type == Date && TypeUtils.isDate(value)) {
                            if (eachFlag) {
                                const idx = args.value.indexOf(value)
                                value = new Date(value)
                                args.value[idx] = value
                            } else {
                                value = new Date(value) as any
                                (args.object as any)[args.property] = value
                            }
                        }
                        const res = TypeUtils.is(value, type)
                        if (!res) {
                            // 类型不匹配，直接返回false
                            return false
                        }

                        // 类型匹配上了（说明不会再匹配其他类型），需要内部进一步校验；但是必须是自定义复杂类型，Number这些没有必要
                        if (validationOptions?.validateNested && value != null && typeof value === 'object') {
                            const resMsgs = validateClass(value, type)
                            if (resMsgs.length > 0) {
                                nestedErr = true
                                if (eachFlag) {
                                    itemsValidatedErrMsgs.push(`${JSON.stringify(value)}元素内部校验失败: ${JSON.stringify(resMsgs.map(e => e.constraints))}`)
                                } else {
                                    itemsValidatedErrMsgs.push(`${JSON.stringify(resMsgs.map(e => e.constraints))}`)
                                }
                                return false
                            }
                        }
                        return true
                    })

                    // 说明这个元素检测失败，且是因为类型不匹配
                    if (!result && eachFlag && !nestedErr) {
                        itemsValidatedErrMsgs.push(`${JSON.stringify(value)}元素无法匹配其中之一类型: ${types.map(t => TypeUtils.transferString(t)).toString()}`)
                    }
                    return result
                },

                /// validate执行完返回了false则会同步进入到这里
                defaultMessage(args?: ValidationArguments) {
                    let types: any[] = []
                    const eachFlag = validationOptions?.each === true && args!.value instanceof Array
                    if (eachFlag) {
                        types = eachTypes as any
                    } else {
                        types = originTypes as any
                    }

                    let result: string = ''
                    const prefix = eachFlag ? `字段${args!.property}在each模式下值: ${JSON.stringify(args!.value)} ` : `字段${args!.property}的值: ${JSON.stringify(args!.value)}`
                    if (types.length === 1) {
                        if (itemsValidatedErrMsgs.length !== 0) {
                            if (eachFlag) {
                                result = `${prefix}无法匹配类型: ${TypeUtils.transferString(types[0])}, 因为存在元素校验错误: ${itemsValidatedErrMsgs.toString()}`
                            } else {
                                result = `${prefix}无法匹配类型: ${TypeUtils.transferString(types[0])}, 因为此字段存在校验错误: ${itemsValidatedErrMsgs.toString()}`
                            }
                        } else {
                            result = `${prefix}无法匹配类型: ${TypeUtils.transferString(types[0])}`
                        }
                    } else {
                        if (itemsValidatedErrMsgs.length !== 0) {
                            result = `${prefix}无法匹配类型列表: ${types.map(t => TypeUtils.transferString(t)).join(' 或 ')}, 因为存在元素校验错误: ${itemsValidatedErrMsgs.toString()}`
                        } else {
                            result = `${prefix}无法匹配类型列表: ${types.map(t => TypeUtils.transferString(t)).join(' 或 ')}`
                        }
                    }

                    // 重置内部校验异常信息
                    if (eachFlag) {
                        itemsValidatedErrMsgs.length = 0
                    }
                    return result
                },
            }
        })
    }
}